﻿#pragma once
#include "zyBase.h"


int DarkMoonUI::zyBase::GetFunKeyState() {
    int ret = 0;
    if (GetAsyncKeyState(VK_CONTROL) & 0x8000) ret |= 0x1;
    if (GetAsyncKeyState(VK_SHIFT) & 0x8000) ret |= 0x2;
    if (GetAsyncKeyState(VK_MENU) & 0x8000) ret |= 0x4;
    return ret;
}

BOOL DarkMoonUI::zyBase::SysHotKeyHandler(HWND hWnd, const std::wstring& className, wchar_t wchr) {
    if (IsWindow(hWnd)) {
        wchar_t hotKeybuf[2] = {'&', wchr};
        wchar_t* lpNameBuff = new wchar_t[MAX_PATH];

        HWND hWndNext = FindWindowExW(hWnd, NULL, NULL, NULL);
        while (hWndNext) {
            if (GetClassNameW(hWndNext, lpNameBuff, MAX_PATH) > 0 && className == lpNameBuff) {
                int len = GetWindowTextLengthW(hWndNext) + 1;
                if (len > 0) {
                    if (GetWindowTextW(hWndNext, lpNameBuff, MAX_PATH) > 0) {
                        if (wcsstr(lpNameBuff, hotKeybuf)) {
                            HWND hwndParent = GetParent(hWndNext);
                            if (hwndParent != nullptr) {
                                auto id = GetWindowLongPtrW(hWndNext, GWL_ID);
                                SendMessage(hwndParent, WM_COMMAND, MAKEWPARAM(id, BN_CLICKED), (LPARAM)hWndNext);
                                return TRUE;
                            }
                        }
                    }
                }
            }
            hWndNext = FindWindowExW(hWnd, hWndNext, nullptr, nullptr);
        }
        delete[] lpNameBuff;
    }
    return FALSE;
}


void DarkMoonUI::zyBase::zyBase_Destroy(zyObject* obj) {
    zyBase_OnNCDestroy(obj);
    obj->removeStringData(L"Name");
}

void DarkMoonUI::zyBase::zyBase_OnNCDestroy(zyObject* obj) {
    HWND hWnd = (HWND)obj->getPtrData(L"hWnd");
    if (hWnd) {
        LONG_PTR oldWndProc = (LONG_PTR)obj->getPtrData(L"oldWndProc");
        if (oldWndProc) {
            SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc);
            obj->removePtrData(L"oldWndProc");
        }
        zyEnv::getInstance().unregisterWnd(hWnd);
        obj->removePtrData(L"hWnd");
    }
    zyObject* layout = (zyObject*)obj->getPtrData(L"zyLayout");
    if (layout) {
        layout->release();
        obj->removePtrData(L"zyLayout");
    }
    obj->removePtrData(L"isMoveIn");
}

LRESULT CALLBACK DarkMoonUI::zyBase::zyBase_WndProc(zyObject* obj, HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL* bHandled) {
    LRESULT ret = 0;
    *bHandled = FALSE;
    auto pEvent = obj->getRegEvent(L"OnWndMsg");
    if (pEvent) {
        ret = pEvent->handler<LRESULT>(hWnd, uMsg, wParam, lParam, bHandled);
        if (*bHandled)
            return ret;
    }
        
    switch (uMsg) {
    case WM_NCDESTROY:
        zyBase_OnNCDestroy(obj);
        break;
    case WM_PAINT: {
        pEvent = obj->getRegEvent(L"OnPaint");
        auto hRgn = (HRGN)obj->getPtrData(L"WindowhRgn");
        if (hRgn)
            SetWindowRgn(hWnd, hRgn, TRUE);
        if (pEvent) {
            PAINTSTRUCT ps = { 0 };
            BeginPaint(hWnd, &ps);
            ret = pEvent->handler<LRESULT>(hWnd, ps.hdc, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right, ps.rcPaint.bottom);
            *bHandled = TRUE;
            EndPaint(hWnd, &ps);
        }
        if (*bHandled)
            return ret;
    } 
    break;
    // 鼠标左键被按下
    case WM_LBUTTONDOWN:
    {
        pEvent = obj->getRegEvent(L"OnLButtonDown");
        if (pEvent) {
            ret = pEvent->handler<LRESULT>(hWnd, LOWORD(lParam), HIWORD(lParam), GetFunKeyState());
            if (ret) {
                *bHandled = TRUE;
                return ret;
            }
        }
    }
    break;
    // 鼠标左键被释放
    case WM_LBUTTONUP:
    {
        pEvent = obj->getRegEvent(L"OnLButtonUp");
        if (pEvent) {
            ret = pEvent->handler<LRESULT>(hWnd, LOWORD(lParam), HIWORD(lParam), GetFunKeyState());
            if (ret) {
                *bHandled = TRUE;
                return ret;
            }
        }
    }
    break;
    // 鼠标左键双击
    case WM_LBUTTONDBLCLK:
    {
        pEvent = obj->getRegEvent(L"OnLButtonDblClk");
        if (pEvent) {
            ret = pEvent->handler<LRESULT>(hWnd, LOWORD(lParam), HIWORD(lParam), GetFunKeyState());
            if (ret) {
                *bHandled = TRUE;
                return ret;
            }
        }
    }
    break;
    // 鼠标右键被按下
    case WM_RBUTTONDOWN:
    {
        pEvent = obj->getRegEvent(L"OnRButtonDown");
        if (pEvent) {
            ret = pEvent->handler<LRESULT>(hWnd, LOWORD(lParam), HIWORD(lParam), GetFunKeyState());
            if (ret) {
                *bHandled = TRUE;
                return ret;
            }
        }
    }
    break;
    // 鼠标右键被释放
    case WM_RBUTTONUP:
    {
        pEvent = obj->getRegEvent(L"OnRButtonUp");
        if (pEvent) {
            ret = pEvent->handler<LRESULT>(hWnd, LOWORD(lParam), HIWORD(lParam), GetFunKeyState());
            if (ret) {
                *bHandled = TRUE;
                return ret;
            }
        }
    }
    break;
    // 鼠标移动
    case WM_MOUSEMOVE: {
        if (obj->hasPtrData(L"EnlableHover")) {
            auto isMoveIn = (size_t)obj->getPtrData(L"isMoveIn");
            if (isMoveIn == 0) {
                obj->setPtrData(L"isMoveIn", (void*)1);

                pEvent = obj->getRegEvent(L"OnMouseIn");
                if (pEvent)
                    ret = pEvent->handler<LRESULT>(hWnd, LOWORD(lParam), HIWORD(lParam), GetFunKeyState());
                TRACKMOUSEEVENT tme = {
                    sizeof(tme),
                    TME_HOVER | TME_LEAVE,
                    hWnd,
                    HOVER_DEFAULT };
                TrackMouseEvent(&tme);
            }
        }
        pEvent = obj->getRegEvent(L"OnMouseMove");
        if (pEvent) {
            ret = pEvent->handler<LRESULT>(hWnd, LOWORD(lParam), HIWORD(lParam), GetFunKeyState());
            if (ret) {
                *bHandled = TRUE;
                return ret;
            }
        }
    } 
    break;
    // 鼠标离开
    case WM_MOUSELEAVE: case 674:
    {
        obj->setPtrData(L"isMoveIn", (void*)0);
        pEvent = obj->getRegEvent(L"OnMouseLeave");
        if (pEvent)
            pEvent->handler<LRESULT>(hWnd);
    }
    break;
    // 鼠标悬停
    case WM_MOUSEHOVER:
    {
        pEvent = obj->getRegEvent(L"OnMouseHover");
        if (pEvent)
            pEvent->handler<LRESULT>(hWnd);
    }
    break;
    // 获取焦点
    case WM_SETFOCUS:
    {
        pEvent = obj->getRegEvent(L"OnSetFocus");
        if (pEvent)
            pEvent->handler<LRESULT>(hWnd);
    }
    break;
    // 失去焦点
    case WM_KILLFOCUS:
    {
        pEvent = obj->getRegEvent(L"OnKillFocus");
        if (pEvent)
            pEvent->handler<LRESULT>(hWnd);
    }
    break;
    // 键盘按下
    case WM_KEYDOWN:
    case WM_SYSKEYDOWN:
    {
        pEvent = obj->getRegEvent(L"OnKeyDown");
        if (pEvent) {
            ret = pEvent->handler<LRESULT>(hWnd, wParam, GetFunKeyState());
            if (ret) {
                *bHandled = TRUE;
                return ret;
            }
        }
    }
    break;
    // 键盘释放
    case WM_KEYUP:
    case WM_SYSKEYUP:
    {
        pEvent = obj->getRegEvent(L"OnKeyUp");
        if (pEvent) {
            ret = pEvent->handler<LRESULT>(hWnd, wParam, GetFunKeyState());
            if (ret) {
                *bHandled = TRUE;
                return ret;
            }
        }
    }
    break;
    // 滚轮滚动
    case WM_MOUSEWHEEL:
    {
        pEvent = obj->getRegEvent(L"OnMouseWheel");
        if (pEvent)
            pEvent->handler<LRESULT>(hWnd, GET_WHEEL_DELTA_WPARAM(wParam), GetFunKeyState());
    }
    break;
    // 字符输入
    case WM_CHAR:
    {
        pEvent = obj->getRegEvent(L"OnChar");
        if (pEvent) {
            ret = pEvent->handler<LRESULT>(hWnd, wParam);
            if (ret) {
                *bHandled = TRUE;
                return ret;
            }
        }
    }
    break;
    //滚动条滚动
    case WM_HSCROLL:
    case WM_VSCROLL: {
        auto pObj = zyEnv::getInstance().getWndObject((HWND)lParam);
        if (pObj)
            return pObj->callChildWndProc(hWnd, uMsg, wParam, lParam, bHandled);
    } break;
    // 命令消息
    case WM_COMMAND: 
    {
        auto Ptr = zyEnv::getInstance().getWndObject((HWND)lParam);
        if (Ptr) {
            return Ptr->callChildWndProc(hWnd, uMsg, wParam, lParam, bHandled);
        }
    } 
    break;
    // 通知消息
    case WM_NOTIFY: {
        zyObject* pObj = NULL;
        auto nh = *reinterpret_cast<NMHDR*>(lParam);
        if (nh.code == TTN_NEEDTEXTW)
            pObj = zyEnv::getInstance().getWndObject(hWnd);
        else
            pObj = zyEnv::getInstance().getWndObject(nh.hwndFrom);
        if (pObj)
            return pObj->callChildWndProc(hWnd, uMsg, wParam, lParam, bHandled);
    } break;
    // 绘制项目
    case WM_DRAWITEM: {
        DRAWITEMSTRUCT dis = *(DRAWITEMSTRUCT*)lParam;
        auto pObj = zyEnv::getInstance().getWndObject(dis.hwndItem);
        if (pObj)
            return pObj->callChildWndProc(hWnd, uMsg, wParam, lParam, bHandled);
    } break;
    // 拖放文件
    case WM_DROPFILES: {
        pEvent = obj->getRegEvent(L"OnDropFiles");
        if (pEvent) {
            UINT countDrop = DragQueryFileW((HDROP)wParam, -1, NULL, 0);
            WCHAR szFile[MAX_PATH] = {0};
            std::wstring files;
            int len;
            for (UINT i = 0; i < countDrop; i++) {
                len = DragQueryFileW((HDROP)wParam, i, szFile, MAX_PATH);
                if (len > 0) {
                    files += szFile;
                    if (i + 1 < countDrop)
                        files += L"\r\n";
                }
            }
            pEvent->handler<LRESULT>(hWnd, files.c_str());
            DragFinish((HDROP)wParam);
            *bHandled = TRUE;
            return 0;
        }
    }
    // 定时器消息
    case WM_TIMER:
    {
        pEvent = obj->getRegEvent(L"OnTimer");
        if (pEvent) {
            pEvent->handler<LRESULT>(hWnd, wParam);
            *bHandled = TRUE;
            return 0;
        }
    }
    break;
    // 列表消息
    case WM_MEASUREITEM:
    case WM_DELETEITEM:
    case WM_COMPAREITEM: {
        {
            auto hWndChild = GetDlgItem(hWnd, (int)wParam);
            if (hWndChild) {
                auto pObj = zyEnv::getInstance().getWndObject(hWndChild);
                if (pObj) {
                    ret = pObj->callChildWndProc(hWnd, uMsg, wParam, lParam, bHandled);
                    if (*bHandled)
                        return ret;
                }
            }
        }
    }
    break;
    // 大小改变
    case WM_SIZE: {
        auto layout = (zyObject*)obj->getPtrData(L"zyLayout");
        if (layout) {
            layout->callWndProc(hWnd, zyLYM_SETSIZE, LOWORD(lParam), HIWORD(lParam), bHandled);
            layout->callWndProc(hWnd, zyLYM_LAYOUT, LOWORD(lParam), HIWORD(lParam), bHandled);
        }
        break;
    }
    // 系统字符键
    case WM_SYSCHAR: {
        auto hWndParent = GetAncestor(hWnd, GA_ROOT);
        if (SysHotKeyHandler(hWndParent, L"Button", (wchar_t)wParam)) {
            *bHandled = TRUE;
            return 0;
        }
        if (SysHotKeyHandler(hWndParent, L"zyButton", (wchar_t)wParam)) {
            *bHandled = TRUE;
            return 0;
        }
    } break;
    default: {
        // 静态控件 编辑控件 列表控件 设置背景或前景色
        if (uMsg >= WM_CTLCOLORMSGBOX && uMsg <= WM_CTLCOLORSTATIC) {
            zyObject* pObj = zyEnv::getInstance().getWndObject((HWND)lParam);
            if (pObj != nullptr) {
                ret = pObj->callChildWndProc(hWnd, uMsg, wParam, lParam, bHandled);
                if (*bHandled)
                    return ret;
            }
        } break;
    }
    }
    return 0;
}

LRESULT CALLBACK DarkMoonUI::zyBase::zyBase_ChildWndProc(zyObject* obj, HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL* bHandled) {
    //std::cout << "WM_COMMAND: " << (uMsg == WM_COMMAND) << std::endl;
    return 0;
}


// class zyBase {
// public:
//     zyBase() : m_obj(new zyObject()) {}

//     zyObject* getObject() const { return m_obj; }
//     void setObject(zyObject* obj) {
//         m_obj->release();
//         m_obj = obj;
//         m_obj->addRef();
//     }

//     std::wstring getName() const { return m_obj->getStringData(L"Name"); }

//     void setName(const std::wstring& name) { m_obj->setStringData(L"Name", name); }

//     std::wstring getType() const { return m_obj->getStringData(L"Type"); }

//     void setType(const std::wstring& type) { m_obj->setStringData(L"Type", type); }

//     void setHwnd(HWND hwnd) { m_obj->setPtrData(L"Hwnd", hwnd); }

//     HWND getHwnd() const { return (HWND)m_obj->getPtrData(L"Hwnd"); }

//     LONG_PTR getBorder() const { return (LONG_PTR)m_obj->getPtrData(L"Border"); }

//     void setBorder(LONG_PTR border) { m_obj->setPtrData(L"Border", (void*)border); }

//     bool hasBorder() const { return m_obj->hasPtrData(L"Border"); }

// private:
//     zyObject* m_obj;
// };